home *** CD-ROM | disk | FTP | other *** search
- /*************************************************************************************************
- *
- *
- * ObjectMacZapp -- a standard Mac OOP application template
- *
- *
- *
- * ZEventHandler.cpp -- the event handler object
- *
- *
- *
- *
- *
- * © 1996, Graham Cox
- *
- *
- *
- *
- *************************************************************************************************/
-
- #include "ZEventHandler.h"
- #include "MacZoop.h"
- #include "ZWindow.h"
- #include "ZCommander.h"
- #include "ZDialog.h"
-
- #include <LowMem.h>
-
- // gSleep is the sleep period passed to WaitNextEvent
-
- short gSleep = kFrontSleep;
-
- // gCurHandler is the current ZCommander object that wants to handle commands. This will
- // usually be the active window or the application
-
- ZCommander* gCurHandler = NULL;
-
- // prototype of handler function for apple-events- sends them up the command chain.
-
- static pascal OSErr ZAEHandler ( AppleEvent* aeEvt, AppleEvent* reply, long refCon );
-
- // global UPP to same
-
- AEEventHandlerUPP gAEUPP = NewAEEventHandlerProc( ZAEHandler );
-
-
- /*-------------------------------*** CONSTRUCTOR ***---------------------------------*/
-
- ZEventHandler::ZEventHandler()
- {
- clicks = 0;
- inBackground = FALSE;
-
- gCurHandler = gApplication;
- }
-
-
- /*---------------------------------*** GETANEVENT ***---------------------------------*/
- /*
-
- gets the next event off the queue. If it's a null event, give idle time
-
- ----------------------------------------------------------------------------------------*/
-
- void ZEventHandler::GetAnEvent( const short mask )
- {
- // gets an event from the event queue and sets "theEvent" to it.
-
- if (! WaitNextEvent( mask, &theEvent, gSleep, NULL ))
- PassIdle();
-
- // dispatch the cursor to the current window, so it's shape can be set. If the cursor is animating,
- // we assume that it was set on purpose for a lengthy operation, so we do not dispatch the cursor
- // in this case. The animating cursor will be cancelled when the application gets a null event.
-
- if (! CursorAnimating())
- {
- ZWindow* aZW = gWindowManager->LocateWindow( theEvent.where );
- WindowPtr w = NULL;
-
- if ( aZW )
- w = aZW->GetMacWindow();
-
- if ( w )
- {
- // check to see that the window is not "windowshaded"- if
- // it is, don't dispatch the cursor. If the window is shaded,
- // its contRgn will be empty.
-
- if (! EmptyRgn( ((WindowPeek) w)->contRgn ))
- {
- if ( aZW )
- {
- Point mouse;
- GrafPtr savePort;
-
- mouse = theEvent.where;
-
- GetPort( &savePort );
- SetPort( w );
-
- GlobalToLocal( &mouse );
- SetPort( savePort );
-
- // if the point is inside the window, dispatch to the window,
- // otherwise reset the cursor to an arrow. If the window is not the top
- // window, the cursor is not dispatched, but reset, unless the window is
- // a floater, in which case we do dispatch it if there not a modal dialog
- // in front of it. The result is correct for what the user expects.
-
- if ( PtInRect( mouse, &w->portRect ) &&
- ( aZW == gApplication->GetFrontWindow() ||
- ( aZW->Floats() && ! gWindowManager->IsDialog( gApplication->GetFrontWindow()))))
- aZW->AdjustCursor( mouse, theEvent.modifiers );
- else
- SetCursor( &qd.arrow );
- }
- }
- else
- SetCursor( &qd.arrow );
- }
- else
- SetCursor( &qd.arrow );
- }
- }
-
-
- /*-----------------------------*** DISPATCHANEVENT ***--------------------------------*/
- /*
-
- determine what sort of event it is and call the relevant handler method.
-
- ----------------------------------------------------------------------------------------*/
-
- void ZEventHandler::DispatchAnEvent()
- {
- // dispatches the event according to its type, etc
-
- Boolean isAutoKey = FALSE;
- char theKey;
-
- // see if this is a dialog event and process it. Note that for floaters to work, we can't use
- // IsDialogEvent, since it assumes FrontWindow() returns the active document- with floaters,
- // this is not true, so we have to ask our own wMgr object to check for us.
-
- if ( gWindowManager->CheckDialogEvent( &theEvent ))
- {
- // allow the event to be modified before the dialog processes it.
- if ( PrefilterDialogEvent())
- return; // event was fully handled
- }
-
- switch ( theEvent.what )
- {
- case mouseDown:
- HandleMouseEvent( theEvent );
- break;
- case activateEvt:
-
- // following defined in ZWindowManager.h
-
- #ifdef _ACTIVATE_EVENTS_ARE_REAL
- HandleWindowActivate( (WindowPtr) theEvent.message,
- (theEvent.modifiers & activeFlag) );
- #endif
- break;
- case autoKey:
- isAutoKey = TRUE;
- case keyDown:
- theKey = theEvent.message & charCodeMask;
-
- HandleKeyEvent( theKey, isAutoKey );
- break;
- case updateEvt:
- HandleWindowUpdate((WindowPtr) theEvent.message );
- break;
- case diskEvt:
- {
- Point dPt = {100,100};
-
- if( HiWord( theEvent.message ) != 0)
- DIBadMount( dPt, theEvent.message );
- break;
- }
- case kHighLevelEvent:
- HandleHLEvent( theEvent );
- break;
- case osEvt:
- HandleOSEvent( theEvent );
- break;
- }
- }
-
-
- /*------------------------------*** HANDLEKEYEVENT ***--------------------------------*/
- /*
-
- process keystrokes. Command-Key sequences are passed to the menu handler
- ----------------------------------------------------------------------------------------*/
-
- void ZEventHandler::HandleKeyEvent( const char theKey, const Boolean isAutoKey )
- {
- long mSelect;
-
- if ( theEvent.modifiers & cmdKey )
- {
- // if this is a command-key combination, translate this to a
- // menu command as if it were picked from the menu.
-
- if (! isAutoKey)
- {
- gMenuBar->DimMenus();
-
- // ask the command chain to reenable the relevant menu items
-
- if ( gCurHandler )
- gCurHandler->UpdateMenus();
-
- mSelect = MenuKey( theKey );
-
- gMenuBar->DispatchCommand( mSelect );
- }
- return;
- }
-
- // the user is typing- send the characters to the current commander
-
- if( gCurHandler )
- gCurHandler->Type( theKey );
- }
-
-
-
-
- /*---------------------------*** PROCESSDIALOGEVENT ***-------------------------------*/
- /*
-
- a modeless dialog is up and the user clicked one of its enabled items. Override this to
- process it for the dialog. This passes clicks for ZDialogs to its ClickItem method
-
- ----------------------------------------------------------------------------------------*/
-
- void ZEventHandler::ProcessDialogEvent( const DialogPtr theDialog, const short itemHit )
- {
- // if this is a ZDialog object, call it's ClickItem method
-
- ZDialog* aZD = (ZDialog*) GetWRefCon( theDialog );
-
- if( aZD )
- aZD->ClickItem( itemHit );
- }
-
-
-
- /*-------------------------*** PREFILTERDIALOGEVENT ***-------------------------------*/
- /*
-
- opportunity to prefilter the event for a dialog before the dialog manager gets it. This
- determines which dialog object to call, and calls its filter function. This is how
- return and enter keys, etc, are processed.
-
- ----------------------------------------------------------------------------------------*/
-
- Boolean ZEventHandler::PrefilterDialogEvent()
- {
- Boolean handled = FALSE;
-
- ZDialog* zDW = dynamic_cast<ZDialog*> ( gApplication->GetFrontWindow());
-
- if ( zDW )
- handled = zDW->Filter( &theEvent );
-
- return handled;
- }
-
-
- /*-------------------------------*** COUNTCLICKS ***----------------------------------*/
- /*
-
- count up the number of rapid mouse-clicks to detect double-clicks, etc.
-
- ----------------------------------------------------------------------------------------*/
-
- void ZEventHandler::CountClicks( const WindowPtr target, const long clickTicks, const Point globalMouse )
- {
- static WindowPtr prevTarget = NULL;
- static long lastClickTicks = 0;
- static Point lastClick = {0,0};
-
- GrafPtr savePort;
- Point gMouse;
-
- gMouse = globalMouse;
-
- GetPort( &savePort );
- SetPort( target );
- GlobalToLocal( &gMouse );
-
- if (target == prevTarget)
- {
- // the target window is the same as the last click, is the click
- // within the double-click period set by the user?
-
- if ( clickTicks < lastClickTicks + GetDblTime())
- {
- // yes, the click is in time. Finally, we ask the window
- // whether we should consider the click as being in the same place.
-
- ZWindow* zW = GetZWindow( target );
-
- if ( zW && zW->ClickInSamePlace( lastClick, gMouse ))
- clicks++;
- else
- clicks = 1;
- }
- else
- clicks = 1;
- }
- else
- clicks = 1;
-
- // store the click point, target and click time for the next time
-
- lastClick = gMouse;
- prevTarget = target;
- lastClickTicks = clickTicks;
-
- SetPort( savePort );
- }
-
-
- /*---------------------------*** HANDLEMOUSEEVENT ***---------------------------------*/
- /*
-
- handle mouse button clicks. This finds the target window or other part of the screen
-
- ----------------------------------------------------------------------------------------*/
-
- void ZEventHandler::HandleMouseEvent( const EventRecord& theEvent)
- {
- WindowPtr targetWindow;
- short partCode;
- long mSelect;
- Point mousePt;
- ZWindow* zappWindow;
-
- // find out what part of the screen the mouse was clicked on
-
- partCode = FindWindow( theEvent.where, &targetWindow );
-
- // if it was any sort of window, get the ZWindow object associated with it, if any.
-
- if ( targetWindow )
- zappWindow = GetZWindow( targetWindow );
-
- switch (partCode)
- {
- case inDesk:
- break;
-
- case inMenuBar:
- // the user clicked the menubar.
-
- gMenuBar->ClickMenuBar( theEvent.where );
-
- break;
-
- case inSysWindow:
- SystemClick( &theEvent, targetWindow ); // system will handle it (DA window)
- break;
-
- case inContent:
- if ( targetWindow ) // the user clicked in a window
- {
- // if there's a modal dialog up, clicks in other windows result in a beep.
-
- ZDialog* aZD = dynamic_cast<ZDialog*> ( gApplication->GetFrontWindow());
- Boolean dialogUp = ( aZD && aZD->IsModal());
-
- CountClicks( targetWindow, theEvent.when, theEvent.where ); // double click?
-
- // if the window is top window or top floater, pass the click to the window.
-
- if( zappWindow &&
- (zappWindow == gApplication->GetFrontWindow() ||
- (zappWindow == gWindowManager->GetTopFloater() && ! dialogUp )))
- {
- // if the window is already active, pass the click to the window object
- // in its local coordinate system.
-
- mousePt = theEvent.where;
-
- zappWindow->Focus();
- GlobalToLocal( &mousePt );
- zappWindow->Click( mousePt, theEvent.modifiers );
- }
- else
- {
- // if the window wasn't active, make it active. If there is a modal dialog in
- // front, then this action is not permitted.
-
- if ( dialogUp )
- {
- SysBeep( 1 );
- break;
- }
- // otherwise, process the click
-
- if ( zappWindow )
- {
- // make this window the active one
-
- zappWindow->Select();
-
- // if the window is a floater, ask it to process the click as well-
- // floaters process "front" clicks even when they were not initially
- // active, since floaters are all 'peers' of one another.
-
- if ( zappWindow->Floats())
- {
- mousePt = theEvent.where;
-
- zappWindow->Focus();
- GlobalToLocal( &mousePt );
- zappWindow->Click( mousePt, theEvent.modifiers );
- }
- }
- }
- }
- break;
-
- case inDrag:
- {
- // the user wants to drag the window. Only permit this if no
- // modal dialog is in front of it, or the command key is down.
-
- ZDialog* aZD = (ZDialog*) gApplication->GetFrontWindow();
-
- if ((((WindowPeek) aZD->GetMacWindow())->windowKind == dialogKind) &&
- aZD->IsModal() &&
- (targetWindow != aZD->GetMacWindow()) &&
- ! (theEvent.modifiers & cmdKey))
- break;
-
- ZWindow* zw = GetZWindow( targetWindow );
- gWindowManager->DragWindowOutline( zw, theEvent.where, theEvent.modifiers );
-
- break;
- }
-
- case inGrow:
- {
- // the user wants to resize the window
-
- Rect szRect;
-
- if ( zappWindow )
- {
- zappWindow->GetSizeRect( &szRect );
-
- szRect.right++;
- szRect.bottom++;
-
- mSelect = GrowWindow( targetWindow, theEvent.where, &szRect );
-
- if ( mSelect )
- {
- // if the command key was down, then we are attempting to override the
- // current settings for sizerect. Thus we need to change the size rect
- // to the desired size first:
-
- if ( theEvent.modifiers & cmdKey )
- {
- szRect.right = MAX( LoWord( mSelect ), szRect.right - 1 );
- szRect.bottom = MAX( HiWord( mSelect ), szRect.bottom - 1 );
-
- zappWindow->SetSizeRect( szRect );
- }
-
- zappWindow->SetSize( LoWord( mSelect ), HiWord( mSelect ));
- }
- }
- break;
- }
-
- case inGoAway:
- if ( TrackGoAway( targetWindow, theEvent.where ))
- {
- // if the user clicks in the go-away box, the window will be closed. If the
- // option key is down, we close all of the windows.
-
- if ( theEvent.modifiers & optionKey )
- gApplication->CloseAll( zappWindow->Floats());
- else
- {
- if ( zappWindow )
- zappWindow->Close( gApplication->GetPhase());
- }
- }
- break;
-
- case inZoomIn:
- case inZoomOut:
- if( TrackBox( targetWindow, theEvent.where, partCode ))
- {
- // if the user clicked in the zoom box, the window will be zoomed
-
- if( zappWindow )
- zappWindow->Zoom( partCode );
- }
- break;
- }
- }
-
-
- /*---------------------------*** HANDLEWINDOWUPDATE ***-------------------------------*/
- /*
-
- to handle an update event, focus the window and ask it do draw its contents.
-
- ----------------------------------------------------------------------------------------*/
-
- void ZEventHandler::HandleWindowUpdate( const WindowPtr theWindow )
- {
- ZWindow* zappWindow = NULL;
- GrafPtr savePort;
- Boolean memState;
-
- if ( theWindow )
- zappWindow = GetZWindow( theWindow );
-
- if ( zappWindow )
- {
- memState = gApplication->memIsShort;
-
- GetPort( &savePort );
- zappWindow->Focus();
-
- BeginUpdate( theWindow );
-
- try
- {
- zappWindow->Draw();
- }
- catch( OSErr err )
- {
- EndUpdate( theWindow );
- SetPort( savePort );
-
- throw err;
- }
-
- EndUpdate( theWindow );
-
- // if the draw resulted in a memory shortage, suppress the warning, since
- // that will trigger further updates, etc.
-
- if ( gApplication->memIsShort != memState )
- gApplication->userHasSeenAlert = TRUE;
-
- SetPort(savePort);
- }
- }
-
-
-
- /*---------------------------------*** PASSIDLE ***-----------------------------------*/
- /*
-
- send the idle command to the current handler, and pass it up the chain
-
- ----------------------------------------------------------------------------------------*/
-
-
- void ZEventHandler::PassIdle()
- {
- // called repeatedly for null events. This passes idle messages to the current commander
-
- if ( gCurHandler )
- gCurHandler->Idle();
-
- // floaters may want idle time too, though they are not part of the command chain. We
- // ask the window manager to give them time:
-
- gWindowManager->FloatIdle();
- }
-
-
-
- /*--------------------------*** HANDLEWINDOWACTIVATE ***------------------------------*/
- /*
-
- calls activate/deactivate for window, and sets up the current handler
-
- ----------------------------------------------------------------------------------------*/
-
- void ZEventHandler::HandleWindowActivate( const WindowPtr theWindow, const Boolean state )
- {
- // handles the activate and deactivate events. This calls the window object with
- // the activate messages, and also sets up gCurHandler.
-
- ZWindow* zappWindow = NULL;
-
- if ( theWindow )
- zappWindow = GetZWindow( theWindow );
-
- if ( zappWindow )
- {
- if ( state )
- {
- zappWindow->Focus();
- zappWindow->Activate();
- gCurHandler = zappWindow->GetHandler();
- }
- else
- {
- zappWindow->Focus();
- zappWindow->Deactivate();
- gCurHandler = zappWindow->GetBoss();
- }
- }
- }
-
-
- /*------------------------------*** HANDLEOSEVENT ***---------------------------------*/
- /*
-
- handle the suspend and resume events sent by MultiFinder/System 7
-
- ----------------------------------------------------------------------------------------*/
-
- void ZEventHandler::HandleOSEvent( const EventRecord& theEvent )
- {
- if ( theEvent.message & suspendResumeMessage )
- {
- inBackground = FALSE;
- gSleep = kFrontSleep;
- gWindowManager->Resume();
- gClipboard->ConvertToPrivate();
- }
- else
- {
- inBackground = TRUE;
- gSleep = kBackSleep;
- gClipboard->ConvertFromPrivate();
- gWindowManager->Suspend();
- }
- }
-
-
- /*------------------------------*** HANDLEHLEVENT ***---------------------------------*/
- /*
-
- handle the high level events sent by AOCE, Applescript, et al.
-
- ----------------------------------------------------------------------------------------*/
-
- void ZEventHandler::HandleHLEvent( const EventRecord& theEvent)
- {
- // handles high level events such as applescript events, etc.
-
- if ( theEvent.message == typeAppleEvent )
- FailOSErr( AEProcessAppleEvent( &theEvent ));
- else
- gApplication->ProcessHLEvent( theEvent );
- }
-
-
- /*-----------------------*** INSTALLAPPLESCRIPTHANDLERS ***---------------------------*/
- /*
-
- install the handler vectors needed to field applescript events. BY default this installs
- the four required events. You can override this to install more, or call the method
- below as needed.
- ----------------------------------------------------------------------------------------*/
-
- void ZEventHandler::InstallApplescriptHandlers()
- {
- InstallAppleEventHandler( kCoreEventClass, kAEOpenApplication );
- InstallAppleEventHandler( kCoreEventClass, kAEOpenDocuments );
- InstallAppleEventHandler( kCoreEventClass, kAEPrintDocuments );
- InstallAppleEventHandler( kCoreEventClass, kAEQuitApplication );
- }
-
-
- /*------------------------*** INSTALLAPPLEEVENTHANDLER ***----------------------------*/
- /*
-
- install the handler vector needed to field all applescript events. Call this once for
- each event class and ID you wish to process. Apple Events will be unpacked by the global
- vector proc and sent up the command chain. You can intercept them there and process them
- as needed.
- ----------------------------------------------------------------------------------------*/
-
- void ZEventHandler::InstallAppleEventHandler( const AEEventClass pClass, const AEEventID pID )
- {
- // installs the AppleEvent hook for the given apple event
-
- if ( gMacInfo.hasAppleEvents )
- FailOSErr( AEInstallEventHandler( pClass, pID, gAEUPP, (long) gApplication, FALSE ));
- }
-
-
- #pragma mark -
- /*---------------------------------*********************---------------------------------*/
-
-
- static pascal OSErr ZAEHandler( AppleEvent* aeEvt, AppleEvent* reply, long refCon )
- {
- // this is the global vector proc that is called for every apple evnt. This determines the
- // event class and ID, then sends that info, plus the event, up the command chain, where,
- // presumably, it will be handled.
-
- AEEventClass pClass;
- AEEventID pID;
- DescType returnedType;
- long returnedSize;
- OSErr theErr = noErr;
-
- try
- {
- // determine the AE class and ID (this is laborious, so it's done here once and passed on)
-
- FailOSErr( AEGetAttributePtr( aeEvt, keyEventClassAttr,
- typeType, &returnedType,
- &pClass, sizeof( AEEventClass ), &returnedSize ));
-
- FailOSErr( AEGetAttributePtr( aeEvt, keyEventIDAttr,
- typeType, &returnedType,
- &pID, sizeof( AEEventID ), &returnedSize ));
-
- // send the event up the command chain
-
- if ( gCurHandler )
- gCurHandler->HandleAppleEvent( pClass, pID, aeEvt, reply );
- else
- theErr = errAEEventNotHandled;
- }
- catch( OSErr err )
- {
- theErr = err;
-
- // exceptions are not propagated, but returned to applescript as
- // an error code
- }
-
- return theErr;
- }
-
-